using System;

namespace Test.ConsoleProgram.Algorithm.Solution
{
    [TestDescription("算法: 0338. 比特位计数")]
    public class No0338_CountBits : AbsBaseTestItem
    {
        /*
        给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ，计算其二进制数中的 1 的数目并将它们作为数组返回。
        示例 1:
            输入: 2
            输出: [0,1,1]
        示例 2:
            输入: 5
            输出: [0,1,1,2,1,2]
        进阶:
            给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗？
            要求算法的空间复杂度为O(n)。
            你能进一步完善解法吗？要求在C++或任何其他语言中不使用任何内置函数（如 C++ 中的 __builtin_popcount）来执行此操作。
        */
        public override void OnTest()
        {
            OnExecute(CountBits_OddAndEven);
            OnExecute(CountBits_OfficialSolution_1);
            OnExecute(CountBits_OfficialSolution_2);
            OnExecute(CountBits_OfficialSolution_3);
            OnExecute(CountBits_OfficialSolution_4);
        }
        private void OnExecute(Func<int, int[]> func)
        {
            Assert.TestExe(func, 2, new int[] { 0, 1, 1 });
            Assert.TestExe(func, 5, new int[] { 0, 1, 1, 2, 1, 2 });
        }

        /// <summary>
        /// 大神思路, 独领风骚!
        /// https://leetcode-cn.com/problems/counting-bits/solution/hen-qing-xi-de-si-lu-by-duadua/
        /// </summary>
        public int[] CountBits_OddAndEven(int num)
        {
            var result = new int[num + 1];
            for (int i = 0; i <= num; i++)
            {
                if (i % 2 == 1)
                {
                    result[i] = result[i - 1] + 1;
                }
                else
                {
                    result[i] = result[i / 2];
                }
            }
            return result;
        }

        /// <summary>
        /// 官方题解, 方法一：直接计算
        /// </summary>
        public int[] CountBits_OfficialSolution_1(int num)
        {
            int countOnes(int x)
            {
                int ones = 0;
                while (x > 0)
                {
                    x &= (x - 1);
                    ones++;
                }
                return ones;
            }
            int[] bits = new int[num + 1];
            for (int i = 0; i <= num; i++)
            {
                bits[i] = countOnes(i);
            }
            return bits;
        }

        /// <summary>
        /// 官方题解, 方法二：动态规划——最高有效位
        /// </summary>
        public int[] CountBits_OfficialSolution_2(int num)
        {
            int[] bits = new int[num + 1];
            int highBit = 0;
            for (int i = 1; i <= num; i++)
            {
                if ((i & (i - 1)) == 0)
                {
                    highBit = i;
                }
                bits[i] = bits[i - highBit] + 1;
            }
            return bits;
        }

        /// <summary>
        /// 官方题解, 方法三：动态规划——最低有效位
        /// </summary>
        public int[] CountBits_OfficialSolution_3(int num)
        {
            int[] bits = new int[num + 1];
            for (int i = 1; i <= num; i++)
            {
                bits[i] = bits[i >> 1] + (i & 1);
            }
            return bits;
        }

        /// <summary>
        /// 官方题解, 方法四：动态规划——最低设置位
        /// </summary>
        public int[] CountBits_OfficialSolution_4(int num)
        {
            int[] bits = new int[num + 1];
            for (int i = 1; i <= num; i++)
            {
                bits[i] = bits[i & (i - 1)] + 1;
            }
            return bits;
        }
    }
}
